package com.mashibing.common.exception;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.mashibing.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

import static com.mashibing.common.exception.BizCodeEnum.*;
import static com.mashibing.common.exception.RequestMethodExceptionEnum.*;

/**
 * 全局处理异常
 *
 * @author ROGzhongyang
 * @date 2024/11/29 22:35:20
 */
@Slf4j
@Order(-100)
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 请求参数缺失异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public R missParamException(MissingServletRequestParameterException e) {
        log.error(">>> 请求参数异常：【{}】【{}】", REQUEST_PARAM_FORMAT_EXCEPTION.getCode(), e.getMessage());
        String parameterType = e.getParameterType();
        String parameterName = e.getParameterName();
        String message = StrUtil.format(">>> 缺少请求的参数 {}，类型为 {}", parameterName, parameterType);
        return R.error(BizCodeEnum.REQUEST_PARAM_FORMAT_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg())
                .put("data", message);
    }

    /**
     * 拦截参数格式传递异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public R httpMessageNotReadable(HttpMessageNotReadableException e) {
        log.error(">>> 参数格式传递异常：【{}】【{}】", REQUEST_PARAM_TYPE_EXCEPTION.getCode(), e.getMessage());
        return R.error(BizCodeEnum.REQUEST_PARAM_TYPE_EXCEPTION.getCode(), BizCodeEnum.REQUEST_PARAM_TYPE_EXCEPTION.getMsg())
                .put("data", e.getMessage());
    }

    /**
     * 拦截参数校验错误异常
     * json 参数
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public R argumentValidExceptionHanlder(MethodArgumentNotValidException e){
        log.error(">>> 全球处理异常 正在工作中...");
//        log.error(">>> 方法参数无效：【{}】【{}】", RequestUtil);
        Map<String, String> map = new HashMap<>();
        e.getFieldErrors().forEach(fieldError -> {
            map.put(fieldError.getField(), fieldError.getDefaultMessage());
            log.error(">>> 请求参数不合法：{},{}", fieldError.getField(), fieldError.getDefaultMessage());
        });
        return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg())
                .put("data", map);
    }

    /**
     * 拦截请求方法的异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public R methodNotSupport(HttpServletRequest request) {
        if (ServletUtil.isPostMethod(request)) {
            log.error(">>> 请求方法异常：【{}】【{}】", REQUEST_METHOD_IS_GET.getCode(), REQUEST_METHOD_IS_GET.getMessage());
            return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg())
                    .put("data", REQUEST_METHOD_IS_GET.getMessage());
        }
        if (ServletUtil.isGetMethod(request)) {
            log.error(">>> 请求方法异常：【{}】【{}】", REQUEST_METHOD_IS_POST.getCode(), REQUEST_METHOD_IS_POST.getMessage());
            return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg())
                    .put("data", REQUEST_METHOD_IS_POST.getMessage());
        }
        return null;
    }

    /**
     * 拦截资源找不到的运行时异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    public R notFound(NoHandlerFoundException e) {
        log.error(">>> 资源不存在异常：【{}】【{}】", RESOURCE_NOT_FOUND_EXCEPTION.getCode(), e.getMessage());
        return R.error(BizCodeEnum.RESOURCE_NOT_FOUND_EXCEPTION.getCode(), BizCodeEnum.RESOURCE_NOT_FOUND_EXCEPTION.getMsg())
                .put("data", RESOURCE_NOT_FOUND_EXCEPTION.getMsg());
    }

    /**
     * 拦截业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public R businessError(BusinessException e) {
        log.error(">>> 全球处理异常 正在工作中...");
        R errorResponseData = R.error(BizCodeEnum.BUSINESS_EXCEPTION.getCode(), BizCodeEnum.BUSINESS_EXCEPTION.getMsg())
                .put(String.valueOf(e.getCode()), e.getMessage());
        log.error(">>> 业务异常：【{}】【{}】", e.getCode(), e.getMessage());
        for (StackTraceElement stackTraceElement : e.getStackTrace()) {
            // 只打印与项目相关的堆栈信息
            if (stackTraceElement.getClassName().startsWith("com.mashibing"))
                log.error(">>> 业务异常堆栈信息：{}", stackTraceElement);
        }
        return errorResponseData;
    }

    /**
     * 拦截服务异常
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public R serviceError(ServiceException e) {
        log.error(">>> 服务异常：【{}】【{}】", SERVICE_EXCEPTION.getCode(), e.getMessage());
        return R.error(BizCodeEnum.SERVICE_EXCEPTION.getCode(), BizCodeEnum.SERVICE_EXCEPTION.getMsg())
                .put("data", e.getMessage());
    }

    /**
     * 处理未知异常
     */
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public R unknownExceptionHanlder(Throwable throwable) {
        log.error(">>> 全球处理异常 正在工作中...");
        log.error("错误信息:", throwable);
        return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg())
                .put("data", throwable.getMessage());
    }
}
